/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.ufg.inf.si.poo.formula1.Season;

import br.ufg.inf.si.poo.formula1.Circuit.Circuit;
import br.ufg.inf.si.poo.formula1.Driver.Driver;
import br.ufg.inf.si.poo.formula1.Library.Library;
import br.ufg.inf.si.poo.formula1.Race.Race;
import br.ufg.inf.si.poo.formula1.Team.Team;

/**
 * Season
 * 
 * Versao 1.0
 * 
 * Data 19/01/2013
 * 
 * @author Igor
 */
public class Season {
    //Atributos
    private Team[] teams;
    private int qttTeams;
    private Driver[] drivers;
    private int qttDrivers;
    private Circuit[] circuits;
    private int qttCircuits;
    private Race[] race;
    private int year;
    private Driver[] driverWorldChampionship;
    private Team[] teamWorldChampionshipBuilders;
    
    //Construtores
    public Season(){
        this.teams = new Team[13];
        this.qttTeams = 0;
        this.drivers = new Driver[52];
        this.qttDrivers = 0;
        this.circuits = new Circuit[20];
        this.qttCircuits = 0;
        this.race = new Race[20];
        this.driverWorldChampionship = new Driver[52];
        this.teamWorldChampionshipBuilders = new Team[13];
    }

    public Season(int year){
        /* Chama o construtor que nao recebe parametro */
        this();
        this.year = year;
    }

    //Metodos Getters and Setters
    /**
     * Retorna o atributo qttTeams (quantidade de equipes na temporada)
     * @return o atributo qttTeams
     */
    public int getQttTeams() {
        return qttTeams;
    }

    /**
     * Altera o atributo qttTeams (quantidade de equipes na temporada)
     * @param o atributo qttTeams
     */
    public void setQttTeams(int qttTeams) {
        this.qttTeams = qttTeams;
    }

    /**
     * Retorna o atributo teams (vetor de equipes da temporada)
     * @return o atributo teams
     */
    public Team[] getTeams() {
        return teams;
    }

    /**
     * Altera o atributo teams (adiciona equipe por equipe aa temporada)
     * @param teams insere equipes na temporada
     */
    public void setTeams(Team teams){
        if(this.qttTeams < 13 && validateTeamInSeason(teams)){
            this.teams[this.qttTeams] = teams;
            if((this.teams[this.qttTeams].getFirstSeason() <= 0)){
                this.teams[this.qttTeams].setFirstSeason(this.year);
            }
            this.qttTeams++;
        }        
    }

    /**
     * Retorna o atributo drivers (vetor de pilotos da temporada)
     * @return o atributo drivers
     */
    public Driver[] getDriver() {
        return drivers;
    }

    /**
     * Altera o atributo drivers (adiciona piloto por piloto aa temporada)
     * @param driver insere pilotos na temporada
     */
    public void setDriver(Driver driver){
        if(this.qttDrivers < 52 && validateDriverInSeason(driver)){
            this.drivers[this.qttDrivers] = driver;
            this.qttDrivers = this.qttDrivers+ 1;
        }        
    }

    /**
     * Retorna o atributo qttDrivers (quantidade de pilotos da temporada)
     * @return o atributo qttDriver
     */
    public int getQttDriver() {
        return qttDrivers;
    }

    /**
     * Altera o atributo qttDrivers (quantidade de pilotos da temporada)
     * @param qttDriver altera a quantidade de pilotos na temporada
     */
    public void setQttDrivers(int qttDriver) {
        this.qttDrivers = qttDriver;
    }

    /**
     * Retorna o atributo circuits (vetor de circuitos da temporada)
     * @return o atributo circuits
     */
    public Circuit[] getCircuits() {
        return circuits;
    }

    /**
     * Altera o atributo circuits (adiciona circuito por circuito aa temporada)
     * @param circuit insere circuitos na temporada
     */
    public void setCircuits(Circuit circuit){
        if((this.qttCircuits < 20) && (validateCircuitInSeason(circuit) == -1)){
            this.circuits[this.qttCircuits] = circuit;
            this.qttCircuits++;
        }        
    }

    /**
     * Retorna o atributo qttCircuits (quantidade de circuitos da temporada)
     * @return o atributo qttCircuits
     */
    public int getQttCircuits() {
        return qttCircuits;
    }

    /**
     * Altera o atributo qttCircuits (quantidade de circuitos da temporada)
     * @param qtdCircuits altera a quantidade de circuitos
     */
    public void setQtdCircuits(int qtdCircuits) {
        this.qttCircuits = qtdCircuits;
    }

    /**
     * Retorna o atributo race (vetor de corridas da temporada)
     * @return o atributo race
     */
    public Race[] getRace() {
        return race;
    }

    /**
     * Altera o atributo race (adiciona corrida por corrida aa temporada)
     * @param race the race to set
     */
    public void setRace(Race race) {
        int indice = validateCircuitInSeason(race.getCircuit());
        if(race.getCircuit() != null){
            if(indice != -1){
                this.race[indice] = race;
            }
        }
    }

    /**
     * Retorna o atributo year (ano em que acontece a temporada)
     * @return o atributo year
     */
    public int getYear() {
        return year;
    }

    /**
     * Altera o atributo year (ano em que acontece a temporada)
     * @param year altera o ano
     */
    public void setYear(int year) {
        this.year = year;
    }

    /**
     * Retorna o atributo driverWorldChampionship (vetor de pilotos participantes da temporada ordenado por pontos, retornando o campeao mundial)
     * @return o atributo driverWorldChampionship
     */
    public Driver[] getDriverWorldChampion() {
        return driverWorldChampionship;
    }

    /**
     * Altera o atributo driverWorldChampionship (vetor de pilotos participantes da temporada ordenado por pontos)
     * @param driverWorldChampionship altera o piloto campeão mundial
     */
    public void setDriverWorldChampion(Driver[] driverWorldChampion) {
        this.driverWorldChampionship = driverWorldChampion;
    }

    /**
     * Retorna o atributo teamWorldChampionshipBuilders (vetor de equipes participantes da temporada ordenado por pontos, retornando o campeao mundial de construtores)
     * @return o atributo teamWorldChampionshipBuilders
     */
    public Team[] getTeamWorldChampionshipBuilders() {
        return teamWorldChampionshipBuilders;
    }

    /**
     * Altera o atributo teamWorldChampionshipBuilders (vetor de equipes participantes da temporada ordenado por pontos)
     * @param teamWorldChampionshipBuilders altera o atributo teamWorldChampionshipBuilders
     */
    public void setTeamWorldChampionshipBuilders(Team[] teamWorldChampionshipBuilders) {
        this.teamWorldChampionshipBuilders = teamWorldChampionshipBuilders;
    }
    
    //Outros Metodos
    /**
     * Ordena o vetor driverWorldChampionship de acordo com a pontuação total de cada piloto
     */
    public void worldChampion(){
        //Copia o vetor de pilotos para o vetor de campeão mundial
        System.arraycopy(this.drivers, 0, this.driverWorldChampionship, 0, this.qttDrivers);

        //Ordena vetor de campeão mundial de acordo com o total de pontos
        for(int i = 0;i < this.qttDrivers-1;i++){
            for(int j = i+1;j < this.qttDrivers;j++){
                if(this.driverWorldChampionship[j].getPoints() > this.driverWorldChampionship[i].getPoints()){
                    Driver driver = this.driverWorldChampionship[i];
                    this.driverWorldChampionship[i] = this.driverWorldChampionship[j];
                    this.driverWorldChampionship[j] = driver;
                }
            }
        }

        //Faz com que o piloto vencedor receba incremento no atributo worldChampionships
        this.driverWorldChampionship[0].setWorldChampionships(this.driverWorldChampionship[0].getWorldChampionships() + 1);
    }
    
    /**
     * Gera o relatório de grid de campeão mundial
     * @return 
     */
    public String printWorldChampion(){
        String data = "";

        data += this.year + " Formula 1 World Champion\n";
        data += "______________________________________________________________\n";
        data += "Pos\tDriver\t\tNationality\tTeam\t\tPoints" + "\n";
        for(int i = 0;i < this.qttDrivers;i++){
            data += i+1 + "\t";
            if(this.driverWorldChampionship[i] != null){
                data += Library.setLengthString(this.driverWorldChampionship[i].getDriverName(), 15) + "\t" ;
                data += Library.setLengthString(this.driverWorldChampionship[i].getNationality(), 15) + "\t" ;
                if(this.driverWorldChampionship[i].getTeam() != null){
                    data += Library.setLengthString(this.driverWorldChampionship[i].getTeam().getShortName(), 15) + "\t" ;
                }else{
                    data += "\t\t";
                }
                data += this.driverWorldChampionship[i].getPoints();
            }
            data += "\n";
        }
        return data;
    }
    
    /**
     * Campeonato Mundial de Construtores
     * Ordena o vetor teamWorldChampionshipBuilders de acordo com a pontuação de cada equipe
     */
    public void worldChampionshipBuilders(){        
        //Copia o vetor de equipes para o vetor de campeonato mundial de construtores
        System.arraycopy(this.teams, 0, this.teamWorldChampionshipBuilders, 0, this.qttTeams);

        //Ordena vetor de campeão mundial de acordo com o total de pontos
        for(int i = 0;i < this.qttTeams-1;i++){
            for(int j = i+1;j < this.qttTeams;j++){
                if(this.teamWorldChampionshipBuilders[j].getPoints() > this.teamWorldChampionshipBuilders[i].getPoints()){
                    Team team = this.teamWorldChampionshipBuilders[i];
                    this.teamWorldChampionshipBuilders[i] = this.teamWorldChampionshipBuilders[j];
                    this.teamWorldChampionshipBuilders[j] = team;
                }
            }
        }
        //Faz com que a equipe vencedora, receba incremento no atributo worldChampionchips
        this.teamWorldChampionshipBuilders[0].setWorldChampionchips(this.teamWorldChampionshipBuilders[0].getWorldChampionchips() + 1);
    }
    
    /**
     * Campeonato Mundial de Construtores
     * Gera o relatório de grid de Campeonato mundial de contrutores
     * @return 
     */
    public String printWorldChampionshipBuilders(){

        String data = "";
        data += this.year + " Formula 1 World Championship Builders\n";
        data += "______________________________________________\n";
        data += "Pos\tTeam\t\t\t\tPoints" + "\n";
        for(int i = 0;i < this.qttTeams;i++){
            data += i+1 + "\t";
            data += Library.setLengthString(this.teamWorldChampionshipBuilders[i].getFullName(), 30) + "\t" ;
            data += this.teamWorldChampionshipBuilders[i].getPoints();
            data += "\n";
        }
        return data;
    }

    /**
     * Verifica se o piloto ja esta presente na temporada
     * @param driver piloto a testar
     * @return true ou false se o piloto ja esta presente na temporada
     */    
    private Boolean validateDriverInSeason(Driver driver){
        for(int i = 0;i < this.qttDrivers;i++){
            if(this.drivers[i].equals(driver)){
                return false;
            }
        }
        return true;
    }

    /**
     * Verifica se a equipe ja esta presente na temporada
     * @param team equipe a testar
     * @return true ou false se a equipe ja esta presente na temporada
     */    
    private Boolean validateTeamInSeason(Team team){
        for(int i = 0;i < this.qttTeams;i++){
            if(this.teams[i].equals(team)){
                return false;
            }
        }
        return true;
    }
    
    /**
     * Remove equipe da season
     * @param team equipe passada como parametro para ser removida
     */
    public void removeTeamSeason(Team team){
        for(int i = 0;i < this.qttTeams;i++){
            if(this.teams[i] != null){
                if(this.teams[i].equals(team)){
                    for(int j = i;j < (this.qttTeams-1);j++){
                        this.teams[j] = this.teams[j+1];
                    }
                    this.teams[this.qttTeams-1] = null;
                    this.qttTeams--;
                }
            }
        }
    }
    
    /**
     * Verifica se o circuit ja esta presente na temporada, retornando seu indice
     * @param team circuit a testar
     * @return indice do circuito, se nao achar retorna -1
     */    
    private int validateCircuitInSeason(Circuit circuit){
        for(int i = 0;i < this.qttCircuits;i++){
            if(this.circuits[i].equals(circuit)){
                return i;
            }
        }
        return -1;
    }

    /**
     * Remove circuito da season (juntamente com sua corrida)
     * @param circuit circuito passado como parametro para ser removido
     */
    public void removeCircuitSeason(Circuit circuit){
        for(int i = 0;i < this.qttCircuits;i++){
            if(this.circuits[i] != null){
                if(this.circuits[i].equals(circuit)){
                    for(int j = i;j < (this.qttCircuits-1);j++){
                        this.circuits[j] = this.circuits[j+1];
                        this.race[j] = this.race[j+1];
                    }
                    this.circuits[this.qttCircuits-1] = null;
                    this.race[this.qttCircuits-1] = null;
                    this.qttCircuits--;
                }
            }
        }
    }

    /**
     * Verifica se a temporada comecou, tesntando o status das corridas
     * (verificar no metodo Race.setStatus(), os valores possiveis para o status)
     * @return verdadeiro ou falso se a temporada ja comecou
     */
    public Boolean validateSeasonStarted(){
        for(int i = 0;i < this.qttCircuits;i++){
            if(this.race[i] != null){
                if(this.race[i].getStatus() == 1 || this.race[i].getStatus() == 2){
                    return true;
                }
            }
        }
        return false;
    }
}
